home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-30 | 77.8 KB | 1,713 lines |
- Spellcaster presents:
-
-
- TTTTTTTTTT HH HH EEEEEEEEEE MM MM AAAA GGGGGGGGG
- TT HH HH EE MMM MMM AA AA GG
- TT HH HH EE MM M M MM AA AA GG
- TT HHHHHHHHHH EEEEEE MM MM MM AAAAAAAA GG
- TT HH HH EE MM MM AA AA GG GGGG
- TT HH HH EE MM MM AA AA GG GG
- TT HH HH EEEEEEEEEE MM MM AA AA GGGGGGGG
-
- Issue 8
- 26-4-96
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- Index:
-
- 1. Introduction
- 1.1. About the magazine
- 1.2. About the author
- 1.3. Distribution
- 1.4. Contribuitions
- 1.5. Hellos and greets
- 2. Mailroom
- 3. Coding sites
- 4. Designing a text adventure - Part I
- 4.1. Plot creation
- 4.2. Plotline
- 4.3. Map creation
- 4.4. Getting started
- 5. Our friend, the pointer - Part III
- 6. How to make a cool starfield
- 7. Sprites Part I - Introduction
- 7.1. Generating images
- 7.2. Killing an image
- 7.3. Displaying an image
- 7.4. Clipping
- 7.5. Saving to the disk
- 7.6. Loading from the disk
- 8. Graphics Part VII - Scrolling Part II
- 8.1. Tile Scrolling
- 8.2. Parallax Scrolling
- 8.3. Partial Scrolls
- 9. Hints and tips
- 10. Points of view
- 11. The adventures of Spellcaster, part 8
-
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
-
- 1. Introduction
-
- 1.1. About the magazine
-
- Welcome to number 8 of 'The Mag', brought to you, as usual, by Spellcaster,
- alias Diogo de Andrade. This is another big issue, so scream in joy ! :)
- I'm very happy !! This is the first issue to feature an article I didn't
- write !! That article is a little bit different from the usual articles. It's
- about were can you get info on programming and other stuff coding-related.
- It was writen by Scorpio (another portuguese dude !!), one of the people
- that most support 'The Mag'... He is also the person that stands all of my
- questions in the MOO I'm trying now... Thanks, man, for beeing there... ;)
- Also, a little add... I'm trying to change the logo on top, the one that
- says 'THE MAG', but my ANSI art sucks !! In fact, all my art sucks !!! I was
- born to code... :) So, if anyone out there wants to do a better logo for me,
- go ahead !!! NOTE- No strange codes, just plain ASCII chars... Not even
- ASCII-E characters, because I use (and sometimes write) this in a UNIX
- machine, and I don't know how to configure the simbols on the screen... :(
-
- This magazine is dedicated to all the programmers and would-be programmers
- out there, especially to those that can't access the Net easily to get
- valuable information, to those who wish to learn how to program anything,
- from demos to games, passing through utilities and all sort of thing your
- mind can think of, and to those that can't find the right information.
-
- When you read this magazine, I'll assume some things. First, I assume you
- have Borland's Turbo Pascal, version 6 and upwards (and TASM for the assembly
- tutorials). I'll also think you have a 80386 (or 386 for short; a 486 would
- be even better), a load of patience and a sense of humor. This last is almost
- essencial, because I don't receive any money for doing this, so I must have
- fun doing it. I will also take for certain you have the 9th grade (or
- equivelent). Finally, I will assume that you have the last issues of
- 'The Mag', and that you have grasped the concepts I tried to transmit. If
- you don't have the issues, you can get them by mail, writing to one of the
- adresses shown below (Snail mail and Email).
-
- As I stated above, this magazine will be made especially for those who don't
- know where to get information, or want it all in the same place, and to those
- who want to learn how to program, so I'll try to build knowledge, building up
- your skills issue by issue. If you sometimes fail to grasp some concept, don't
- despair; try to work it out.
- That's what I did... Almost everything I know was learnt from painfull
- experience. If you re-re-re-read the article, and still can't understand it,
- just drop a line, by mail, or just plain forget it. Most of the things I
- try to teach here aren't linked to each other (unless I say so), so if you
- don't understand something, skip it and go back to it some weeks later. It
- should be clearer for you then. Likewise, if you see any terms or words you
- don't understand, follow the same measures as before.
-
- Ok, as I'm earing the Net gurus and other god-like creatures talking
- already, I'm just going to explain why I use Pascal.
- For starters, Pascal is a very good language, ideal for the beginner, like
- BASIC (yech!), but it's powerfull enough to make top-notch programms.
- Also, I'll will be using assembly language in later issues, and Pascal makes
- it so EASY to use.
- Finally, if you don't like my choice of language, you can stop whining. The
- teory behind each article is very simple, and common with any of the main
- languages (C, C++, Assembly - Yes, that's true... BASIC isn't a decent
- language).
-
- Just one last thing... The final part of the magazine is a little story
- made up by my distorted mind. It's just a little humor I like to write, and
- it hasn't got nothing to do with programming (well, it has a little), but,
- as I said before, I just like to write it.
-
- 1.2. About the author
-
- Ok, so I'm a little egocentric, but tell me... If you had the trouble of
- writing hundreds of lines, wouldn't you like someone to know you, even by
- name ?
-
- My name is Diogo de Andrade, alias Spellcaster, and I'm the creator,
- editor and writer of this magazine.
- I live in a small town called Setubal, just near Lisbon, the capital of
- Portugal... If you don't know where it is, get an encyclopedia, and look for
- Europe. Then, look for Spain. Next to it, there's Portugal, and Setubal is in
- the middle.
-
- I'm 18 years old, and I just made it in to the university (if you do want
- to know, I'm in the Technical Institute of Lisbon, Portugal), so I'm not
- a God-Like creature, with dozens of years of practice (I only program by
- eight years now, and I started in a Spectrum, progressing later to an Amiga.
- I only program in the PC for a year or so), with a mega-computer (I own a
- 386SX, 16 Mhz), that wear glasses with lens that look like the bottom of a
- bottle (I use glasses, but only sometimes), that has his head bigger than a
- pumpkin (I have a normal sized head) and with an IQ of over 220 (mine is
- actually something like 180-190). I can program in C, C++, Pascal, Assembly
- and even BASIC (yech!).
-
- So, if I am a normal person, why do I spend time writing this ?
- Well, because I have the insane urge to write thousands of words every now
- and then, and while I'm at it, I may do something productive, like teaching
- someone. I may be young, but I know a lot about computers (how humble I am;
- I know, modesty isn't one of my qualities).
-
- Just one more thing, if you ever program anything, please send to me... I
- would love to see some work you got, maybe I could learn something with it.
- Also, give me a greet in your program/game/demo... I love seeing my name.
-
- 1.3. Distribution
-
- I don't really know when can I do another issue, so, there isn't a fixed
- space of time between two issues. General rule, I will try to do one every two
- weeks, maybe more, probably less (Eheheheh). This is getting to an issue
- every month, so, I'll think I'll change the above text... :)
- 'The Mag' is available by the following means:
-
- - Snail Mail : My address is below, in the Contributions seccion... Just
- send me a disk and tell me what issues you want, and I
- will send you them...
-
- - E-Mail : If you E-mail me and ask me for some issues, I will Email you
- back with the relevant issues attached.
-
- - BBS's : I don't know for sure what BBS's have or will have my magazine,
- but I will try to post it in the Skyship BBS.
- If you have a BBS and you want to receive 'The Mag', contact me.
-
- Skyship BBS numbers: (351)+01-3158088
- (351)+01-3151435
-
- - Internet : You can access the Spellcaster page and take the issues out
- of there in:
-
- http://alfa.ist.utl.pt/~l42686
-
- - Anonymous ftp: I've put this issue of 'The Mag' on the ftp.cdrom.com
- site... I don't know if they'll accept it there, because
- that's a demo only site, and my mag doesn't cover only
- demos, but anyways, try it out... It has lots of source
- code of demos.
-
- 1.4. Contributions
-
- I as I stated before, I'm not a God... I do make mistakes, and I don't
- have (always) the best way of doing things. So, if you think you've spotted
- an error, or you have thought of a better way of doing things, let me know.
- I'll be happy to receive anything, even if it is just mail saying 'Keep it
- up'. As all human beings, I need incentive.
-
- Also, if you do like to write, please do... Send in articles, they will be
- welcome, and you will have the chance to see your names up in lights.
- They can be about anything, for a review of a book or program that can
- help a programmer, to a point of view or a moan. I'm specially interested in
- articles explaining XMS, EMS, DMA and Soundblaster/GUS.
-
- If anyone out there has a question or wants to see an article about
- something in particular, feel free to write... All letters will be answered,
- provided you give me your address.
-
- I'm also trying to start a new demo/game/utility group, and I need all sort
- of people, from coders (sometimes, one isn't enough), musicians (I can
- compose, but I'm a bit limited), graphics artists (I can't draw nothing) and
- spreaders... I mean, by a spreader, someone who spreads things, like this mag.
- If you have a BBS and you want it to include this magazine, feel free to
- write me... I don't have a modem, so I can only send you 'The Mag' by Email.
-
- You can also contact me personally, if you study on the IST (if you don't
- know what the IST is, you don't study there). I'm the freshman with the
- black hair and dark-brown eyes... Yes, the one that is trying to make people
- believe he can code !! :)
-
- My adress is:
- Praceta Carlos Manito Torres, nº4/6ºC
- 2900 Setúbal
- Portugal
-
- Email: dgan@rnl.ist.utl
- l42686@alfa.ist.utl.pt
-
- And if you want to contact me on the lighter side, get into the Lost Eden
- talker... To do that telnet to:
-
- Alfa.Ist.Utl.Pt : Port 1414
-
- If that server is down, try the Cital talker, in
-
- Zeus.Ci.Ua.PT : Port 6969
-
- I'm almost always there in the afternoon... As you may have guessed already,
- my handle is Spellcaster (I wonder why...)...
-
- 1.5. Hellos and greets
-
- I'll say hellos and thanks to all my friend, especially for those who put
- up with my constant whining.
- Special greets go to Denthor from Asphyxia (for the excelent VGA trainers),
- Draeden from VLA (for assembly tutorials), Joaquim Elder Guerreiro, alias
- Dr.Shadow (Delta Team is still up), Joao Neves for sugestions, testing and
- BBS services, and all the demo groups out there.
- I will also send greets to everybody that responded to my mag... Thank
- you very much !
- Super Very Special thanks go to: Ricardo 'Scorpio' Oliveira...
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 2. Mailroom
-
- Well, I've got another letter telling me I SUCK ! Just kidding... I got
- a letter of someone who noticed one error in a previous issue. It was a
- friend of mine called Nuno, and he studies in the same school as I do, and
- he is also trying to major in Computer Engeneering (hope he doesn't end like
- me and he makes through !)...
- Well, so what's the screw-up, you may ask... And I will answear... In issue
- four, in the graphics section, in the part about circles, I told you that
- Pascal uses reverse-angling, that is, that the trigonometrical circle goes
- in a clockwise direction... Well, this is WRONG !! Pascal goes in the
- standart (anti-clockwise) direction... The reason that made me believe so
- was that in real life, usually the y axis increases the more you go upwards
- and decreases going downwards... But in the computer sense, this goes
- reverse, and that is why I screwed up... Sorry but that ! :)
- Thanks, NSJ !
-
- -----------------------------------------------------------------------------
-
- Other letter I got was from a guy who told me that he got an Heap Overflow
- error, when he runned the same program lot's of times... I've checked the
- program and realized that it was my fault ! I forget to told you, when I
- talked about virtual screens, back in issue 5, that you should de-allocate
- the pointers to the virtual pages, because they are filling the memory.
- So, in the end of the program, when you don't need the virtual screens anymore
- you should call the CloseVirt procedure:
-
- Procedure CloseVirt;
- Var A:Byte;
- Begin
- For A:=1 To Npages Do
- Begin
- Freemem(Virt[A],64000);
- VP[A]:=$A000;
- End;
- End;
-
- Sorry about that... :)
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 3. Coding sites
-
- Ok, this is the article writen by Scorpio (as you will guess)... I,
- Spellcaster will make my coments between square brackets []...
-
- I am Ricardo Manuel Oliveira, aka Scorpio and I live in Portugal...
- [ I already told you that !! :) ]
- I have read all the issues of The Mag (like all of you :)) and I was
- very angry 'cos Spellcaster didn't know the URL of my page (Check 'THE
- MAG #7).. :)...
- He didn't know Denthor's one too, though... :)
- [ So, I'm no URL storing machine !! :) ]
- Now, more seriously:
- This article is a coding-resources list gathered by me... Why have I decided
- to share it with you all? 'Cos I'm happy right now... I have created a
- HTML page about my local soccer club (Vitoria Sport Clube, for portuguese
- people), and it appeared reviewed in a national magazine (CyberNet, for ...)
- So, I have felt that I have to share this joy with lots of people and
- I'm contributing to the growth of 'THE MAG'... Since I read it, I could see
- my name there, right ?
- [ Of course you can !! Write some more !! I like having less work to do ! ]
-
- DEMO-RELATED CODING PAGES:
- --------------------------
-
- http://www.dur.ac.uk/~d405ua/demoftps.html
- Extensive list of demo-related FTP servers (UK)
-
- http://www.cdrom.com/pub/demos/hornet/8086
- 8086 Compo + Coding examples to the 8086
-
- http://196.6.101.37:80/grants/Asphyxya/Asphyxya.html
- Denthor / Asphyxia 's Homepage GREAT vga-coding Tutorials!!!
-
- http://alfa.ist.utl.pt/~l42686/
- Spellcaster's Homepage - 'THE MAG' (general (demo/vga)coding magazine)
- You're reading it
- [ My great page ! He forgot that 'The Mag' also haves stuff about game
- making and the Adventures of Spellcaster !! :) ]
-
- GENERAL-CODING PAGES:
- ---------------------
-
- http://www.cs.vu.nl/~jprins/tp.html
- Turbo Pascal Programmer's page
- If you're into Pascal, CHECK THIS ONE NOW!!!
-
- http://www.interlog.com/~jfanjoy/swag/swag.html
- SWAG Homepage - Pascal code for everybody (_LOTS_ OF CODE)
-
- http://www.fys.ruu.nl/~faber/amain.html
- Faber's Hotlist Assembly links
-
- http://www.cera2.com/assembly
- Assembly Language HotLists and Major Resources
-
- http://www.caiw.nl/~jdbruijn/cl.html
- Code Language Page, by Jack de Bruijn
-
- http://onyx.idbsu.edu/~jcofflan/
- Joe's Assembly Language Page, by Joe :-)
-
- http://www.netrunner.net/~irvinek/asm.htm
- Assembly Language Sources, by Kip P. Irvine
-
- Where can I find CODE?:
- -----------------------
-
- ftp://ftp.cdrom.com/pub/demos/code
- Democoding examples and more... a LOT more
- It's in USA, a bit _SLOW_ for european users during the afternoon...
-
- ftp://ftp.luth.se/pub/msdos/demos
- Mirror of cdrom
- _FAST_ for european users (_VERY_FAST_ indeed :)) (includes FTPMAIL!!!)
-
- ftp://ftp.co.iup.edu/code
- Mirrors cdrom's CODE dir.
- 'Bit slow...
-
- ftp://x2ftp.oulu.fi/pub/msdos/programming
- This place is huge! It'll keep you busy for a LONG time.
-
- ftp://garbo.uwasa.fi/pub/
- Another BIG place... Happy searchin'
-
- Oh, yes... Check the alt.lang.* newsgroups
- [ And the following groups:
- comp.graphics.algorithms
- rec.games.programmer
- comp.programming
- alt.sys.ibm.pc.demos (I think this is it... Search for demos... :) ]
-
- At last, if you want more links try my bookmarks at
- http://wwwalu.ci.uminho.pt:8888/~si17899/bookmark.html
- To contact me, email me at: si17899@ci.uminho.pt
- [ Check it out !! :) ]
-
- Spellcaster, take the lead...
-
- Thanks Scorpio ! Feel free to write some more ! :)
- So, let's move on to the next article...
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 4. Designing a text adventure - Part I
-
- This article is intended for the beginners who want to do games. I know
- that text adventures are definetly out, but the ideas behind a text adventure
- are very similar to those found in graphic adventures, so what I say here
- can be expanded to a graphic adventure...
- Note that these are my personal views on how a text adventure should be
- coded and designed... These articles will teach _EVERY_ step in the creation
- of a text adventure, from designing and plotline creation, to programming, to
- pointers on how to further expand the system...
- There can be some errors and irregularities in the code and explanations,
- because I'm writing this at the same time I'm coding the adventure, so I
- will sometimes make mistakes... If you spot one, or have any doubts, mail me !
-
- 4.1. Plot creation
-
- This part of the article will give you some pointers on how you should start
- to build your text adventure...
- So, for me, one the more important parts of _ANY_ game is the plot... It's
- the first thing I do, because I believe that the other pieces of the game
- (playability and such) will come together, if you have a good story. In this
- stage you must try to be original... Because it's getting harder and harder
- to be original in the plot, you must be original in other things... For
- example, I do most of the story of the game with the idea of SUSPENSE ! I
- like to put the hero in the game with no idea of what he is supposed to
- accomplish... This is my idea... Other piece of originality is the atenction
- to detail... This is also very important, for it adds very much for the
- atmosphere of the game... So, if you follow these ideas, you can make a text
- adventure that is fun to play, even in these DOOM-clones filled times...
- Just for the record, I will state something about Doom... Cool graphics and
- gameplay, crappy story !! I admire the guys at ID software (technically
- speaking), but I would like to shoot their desing department ! :)
- Another important of the detail is to pay heed to the time/space in which
- the game occurs... If you are doing an adventure passed into outer-space, you
- shouldn't put an old Chevy in it... :)
- So, for our text adventure, I will conceive a little stupid story... So, let
- me think... Hum... This is hard... :)
- Ok, I got it! Let's imagine that the hero's uncle has just passed out (on
- the 25 April 1996... This is details, that make up the atmosphere), and he
- had sent you a letter (the letter is dated of the 23 April 1996... Again,
- detail) before he did so, saying that he has a treasure hidden in his
- mansion (that is in a high cliff, near the ocean), and if you can found it,
- it is yours... So, filled with lust for gold, the hero sets foot for the
- mansion. Crappy story, I know, but this one enables me to explain how to
- make a basic text adventure...
- Another thing I think it's very important in a game (of any kind) is the
- title... I don't know, but I spend a lot of time thinking of the name for a
- game... The name should give the user the will to explore the game further...
- So, one possible title for this game should could be 'The Mansion', but
- this doesn't call the atencion... So, you could name it 'Treasure Mansion',
- but this title is crappy, because the word 'treasure' has been used so many
- times in games and titles that has became vulgar... Other examples of words
- like that is 'Prince', 'Princess', 'Dragon'. Let's try another time... How
- about 'Evil Mansion'. It's getting better, but I think it isn't suitable for
- the game yet... We also have variations on the theme: 'Evil Home', 'Home of
- Evil', 'Evil Lair'... But still, altough they are cool, they remember a game
- where there is a house possessed by an evil sorcerer... And this is not the
- case (altough it could be)... The only problem (in this story I'm developing)
- in the house is that it has a couple of monsters/haunts... We could call it
- 'Haunted House', or 'Haunted Mansion', but 'Haunted' is one of those words,
- similar to 'treasure'... So, we can be a bit more inventive, and add to the
- atmosphere. We could say that the name of the mansion is 'Fanglore', and call
- the game just that: 'Fanglore'... using this name, we've added to the
- atmosphere (because we added the detail of the name of the house), and we
- gave a name to the game that make the user not know what is he going to
- see... :) So, the process of creating the great text-adventure 'Fanglore' is
- underway... :)
-
- 4.2. Plotline
-
- Next in the list (for me) is the plotline and map creation. These two steps
- should be made simultaneosly...
- The plotline is the course the game should follow normally...
- In Fanglore, the plotline is:
-
- Going to Fanglore -> Finding the treasure -> Escape the house
-
- A game can have several endings, and different soluttions for the game, and
- that increases the complexity of the plotline (and the overall interest of
- the game)... But the way of doing this is the same.
- Each part of the plotline is a different step of the game. Now, every
- step of the game has different objectives (though the game has only one
- objective). For example, the first step 'Going to Fanglore' has his own
- objective, that is, to enter the mansion. Also, every step of the game has
- a reason of existing... The basic reason is the completion of the game, but
- you must explain, that is, you must know what put the character(s) in that
- particular position. The first step of Fanglore exists because the taxi left
- us at the door of the mansion, that is closed for years, and you don't have
- the key. Also, very step of the game have a way to completing it's objective,
- and that also needs to be defined. Again, in the first step, the way of
- getting into Fanglore is to find a shovel and knock down the door... You
- also have to take in account possible problems and a way to overcome them...
- The problems in a text adventure are not only made of a difficult puzzle to
- resolve; monsters and other similar things also have it's effects... In the
- first part there aren't any problems, but in the second part, there is a
- room that is filled with gas, and you have to use a gas mask to go past that
- room, and to find the mask, you must go to the kitchen of the house and open
- the oven... That is were the mask is...
- So, scematically:
-
- - Going to Fanglore
- Objective ?
- To get into Fanglore.
- Why ?
- Because the cab left us at the door and we don't have the key.
- How ?
- Get the shovel
- Knock down door with it (the door opens)
-
- The other steps of the plotline:
-
- - Finding the treasure
- Objective ?
- Find the treasure.
- Why ?
- Because that is the point of the game.
- How ?
- Go to kitchen
- Open oven
- Get gas mask
- Wear mask
- Go past the gas room
- Find the library
- Push bookshelf (you found a secret passage)
- Go through passage
- You found the vault with the treasure
- Other problems ?
- Monsters in some rooms, that can kill you. You can kill them,
- if you have the sword (that is in the main room)...
-
- - Escape the house
- Objective ?
- Get out of Fanglore.
- Why ?
- Because the passage has closed when you passed through it, and
- you are stuck...
- How ?
- Push a brick in the wall (reveals another secret passage)
- Go through passage
-
- So, the plotline is complete... You should also create a map while you are
- doing the plotline...
-
- 4.3. Map creation
-
- As said, the map should be made at the some time as the plotline. There
- isn't a standart way of doing the map... The ideia is this: In the map, you
- should setup were are going to be the exits of a room (the relantion between
- the various rooms) and you should also number all the rooms.
- The first draft for a map is shown in picture Map01.Pcx. It has six rooms:
-
- 1. Kitchen 2. Main Hall 3. Gate
- 4. Gas Room 5. Library 6. Treasure Room
-
- For the plotline, you already know the importance of each of these rooms.
- The yellow line connecting rooms mean that there is an exit from one to
- another. If there isn't a line, there isn't an exit. The orange dotted line
- means a conditional exit, that is, an exit that is only open at certain times,
- or when you have made something (for example, the exit from room 3 to room 2
- only opens when you break down the door). An arrow on the end of a exitline
- means an unidirectional passage... For example, you can go east from room 5
- to room 6, but you can't go west back to room 5.
-
- But, this doesn't give much to explore, and almost all players like to
- search dozens of rooms... It is part of the detail... For example, in a
- mansion should have a dinning room, and a great garden... Well, these aren't
- present in the draft. And a mansion should also have bedrooms, and Fanglore
- as we designed doesn't have them.
- So, you make a more detailed map... This is in Map02.Pcx. It has 22 rooms.
- The rooms that are in green are the garden-rooms, and the others are the
- mansion-rooms. We've also added the dinning room also. But we didn't added
- the bedroom. Well, if you want, you can ommit certain details, but you have
- to add others. In the case of bedrooms, you can say that there is a stair in
- the Main Hall, that takes you to the upper floor, but the stair is blocked,
- so you can't go that way...
- So, the map is now complete.
-
- 4.4. Getting started
-
- So, let's get started in the coding department... We first should get the
- room data. I've made a little program that enables you to type in the room
- data (with lame source code). Each room is a record that has the exits info,
- and the description of the room. So:
-
- Type RoomType=Record
- Desc:Array[1..10] of String[79];
- North,South,East,West:Byte;
- End;
-
- The description of the room is an array of strings, with only 79 chars per
- string because the screen only has enough space for 80 lines, and you must
- take in acount the return character. You don't need to use the complete 79
- columns, neither the 10 lines of text. You just have to type in a line with
- a single '*' after the last line of text. If you want to use the 10 lines,
- the '*' is left out.
- As you have various rooms, you should have an array with the various rooms:
-
- Const NumberRooms=22;
-
- Var Rooms:Array[1..NumberRooms] of RoomType;
-
- The fields North, South, East and West are a number that indicates to
- what room you should go if you go in that direction. A zero there indicates
- that there isn't an exit in that direction. For example, if Rooms[1].North=2
- then, if you go north in room 1 you will go to room 2.
- Fanglore will use a file called Room.Dat to store the room data.
- So, to end this issue's article in text adventure, here is the procedure
- to read the room data:
-
- Procedure ReadRoomData;
- Var F:Text;
- A,B:Byte;
- Flag:Boolean;
- Begin
- { Prepares the text file for accessing }
- Assign(F,'Room.Dat');
- Reset(F);
- { For every room in the game }
- For A:=1 To NumberRooms Do
- Begin
- { Clear the room's description }
- For B:=1 To 10 Do Rooms[A].Desc[B]:='';
- { Read the description of the room }
- Flag:=True;
- B:=1;
- While Flag Do
- Begin
- Readln(F,Rooms[A].Desc[B]);
- If (B=10) Or (Rooms[A].Desc[B]='*') Then
- Flag:=False;
- Inc(B);
- End;
- { Read exit data }
- Readln(F,Rooms[A].North);
- Readln(F,Rooms[A].South);
- Readln(F,Rooms[A].East);
- Readln(F,Rooms[A].West);
- End;
- Close(F);
- End;
-
- The procedure is self-explainatory, with the exceptions of a few points.
- If you are wondering why do we clear the rooms description before we load,
- if there isn't anything there, this is the answear: Pascal, when it creates
- a variable, puts it anywhere in memory it can fit, but it can be something
- there, and Pascal doesn't erase it... It is good programming pratice to clear
- the comtent of a variable before using it (jee, I sound like one of my
- teachers). Second of all, I don't know if I already showed you what does the
- Inc keyword. The Inc keyword increases the variable given by one (if no other
- parameter is specified). So, Inc(B) is equal to B:=B+1, and Inc(B,2) is equal
- to B:=B+2...
-
- Well, the call to this procedure should be made in a procedure called
- something like Init, which sets up all variables and prepares the game to
- be played. So, procedure Init is (for the moment, for there are other stuff
- to initialize) like this:
-
- Procedure Init;
- Begin
- ReadRoomData;
- End;
-
- And the Init procedure should be called from the main program. So, the
- main program should be like this, for the meanwhile:
-
- Begin
- Init;
- End.
-
- This all is already typed in file FangLore.Pas...
- NOTE: Any file generated with the RoomGen program can be altered by hand,
- that is, you can load it to any ASCII editor and edit any errors
- and alterations you want to make... Don't forget to save as ASCII
- the altered file !
- So, in next issue, I will tell you how to build the phrase parser and some
- of the basic verbs... Until then, try to do it by yourself... :)
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 5. Our friend, the pointer - Part III
-
- Well, this is the last of the articles on pointers... Nobody liked them, so
- I won't waste my time with them anymore... :(
- In this part I will discuss dynamic structures to the highest degree (I'm
- such a liar !! :) ).
- So, let's assume you want to do a database that stores the names and
- phonenumbers of all your friends (if you are like me, you have _LOTS_ of
- friends... :))) ). You could do it in the tradicional manner:
-
- Type FriendRec=Record
- Name:String;
- Phone:String;
- End;
-
- Var Friends:Array[1..100] Of FriendRec;
-
- But this would impose a limit of 100 friends, and you would spend your
- precious variable memory... Even if you increased the size of the array,
- you would have a limit of 128 friends, because you have 2 strings, that
- ocuppy 256 bytes each, and: 2*256*128=65536, that is the maximum memory you
- can allocate for variables... That is no good... You should be able to add
- phonenumbers 'till you run out of memory...
- You could use the method teached in number one, using static pointers, but
- that only enables to use 65536 bytes of memory, and that would only solve
- the problem of lack of variable memory.
- You can use a variant of method 2, that it is what I'm going to teach you.
-
- First, define this:
-
- Type PFriend=^FriendRec;
- FriendRec=Record
- Name:String;
- Phone:String;
- Next:PFriend;
- End;
-
- Var Friends:PFriend;
-
- Ok, you did understand it, did you ?
- Think about this... What we are doing is to create a structure that points
- to a place in memory where a structure of type FriendRec is allocated. In
- the FriendRec structure it is defined another pointer that points to another
- structure of type FriendRec, and so forth... Look at the scheme below... In
- the beggining, variable Friends points to a random position in memory:
-
- Friends --> ?
-
- Then, you allocate the structure associated with variable Friends... To do
- so, you use the New command... So, you do:
-
- New(Friends);
-
- The structure will change and become something like this:
-
- Friends --> Name
- Phone
- Next --> ?
-
- To access now the name and phonenumber of the first friend, you just do:
-
- Friends^.Name:='Diogo Andrade';
- Friends^.Phone:='555-1355';
- Writeln(Friends^.Name);
-
- You should make always: Friends^.Next:=NIL; I will explain the reason
- why later.
- And if you want to create another structure, that is, another friend ?
- Yes, you do:
- New(Friends^.Next);
-
- The structure would look something like this:
-
- Friends --> Name --> Name
- Phone | Phone
- Next ---| Next --> ?
-
- So, the fields would be accessed by:
-
- Friends^.Next^.Name
- Friends^.Next^.Phone
- Friends^.Next^.Next
-
- But, if you increase the number of structures, it would become impossible
- to access them all... So, you use a little trick: you assign an extra variable
- to the first record, and then you go through all of them, like this:
-
- Procedure GoLast;
- Var Tmp:PFriends;
- Begin
- Tmp:=Friends;
- While Tmp^.Next<>NIL Do
- Begin
- Tmp:=Tmp^.Next;
- End;
- .....
- { Tmp now points to the last structure }
- .....
- End;
-
- Now do you understand what does the NIL value is needed for ? To know what
- is the last... :))
- I know this sounds complicated at first, but with pratice it will come to
- you as natural as 2+2=5... :)
- Just a few notes...
- 1) Never loose the pointer to the first position in memory, or else you
- can't access that address... As the matter of fact, you shouldn't loose
- _ANY_ pointer, or else they will become lost pieces of memory you can
- no longer access...
- 2) Don't forget to deallocate the pointers when you end the program, or
- else you will loose the memory on which they are allocated... They don't
- just go away like variables in a Pascal program... They need to be
- deallocated with the Dispose keyword...
-
- Well, I think this wraps it up... As I said earlier, this is the last of the
- pointer articles, so I'm going to start a new series in next issue... I don't
- know what it will be, but I think I'm going to make it about assembly...
- Stay tuned... Spellcaster out... :)
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 6. How too make a cool starfield
-
- This article is about creating a starfield... Remember the starfield
- program I gave in the Graphics article, last issue ? Well, that program
- SUCKED big time ! :) As I don't like beeing regarded as a bad programmer
- (altough I am :) ), here is an article on about how to create a
- starfield... Well, starfields are funny... They are beutifull and exciting...
- And this text is sucking ! :)
- Now, really, the problem of the starfield in issue 7 is that it spent too
- much of the processor (it wasn't efficient, because it moved the entire
- screen, when it only needed to move a few pixels) and it was unreallistic,
- because we all know that stars that are further away from us move slower that
- stars close to us...
- So, let's get down to business... One of the reasons why the starfield of
- last issue's was so slow was that you scrolled _ALL_ the pixels of the screen,
- that is, you did 64000 moves !! That's ridiculous, if you think that the
- screen only had 1000 stars, that is, you could move all the stars using only
- 1000 memory moves... That is 64 times faster !
- So, the ideia is this... You keep track of the coordinates of all the stars,
- and you move them wherever you want...
- Ok, so one star is a record:
-
- Type Star=Record
- X,Y:Integer;
- Color:Byte;
- End;
-
- And lots of stars are an array:
-
- Var Stars:Array[1..1000] Of Star;
-
- Then, you must initialize the stars, the graphics and the palette... We
- will use the Mode13h unit, that was given the last issue:
-
- Procedure Init;
- Var A:Word;
- Begin
- InitGraph;
- { Sets up 16 grays... }
- For A:=0 To 15 Do SetColor(A,A*4,A*4,A*4);
- { Sets up stars }
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Random(320);
- Stars[A].Y:=Random(200);
- Stars[A].Color:=Random(15)+1;
- End;
- End;
-
- Note: If you are wondering why Stars[A].Color:=Random(15)+1, know this:
- 0 <= Random(x) < x ; but, in this example:
- 0 <= Random(15) < 15 ; but a star shouldn't get color 0, so we add
- one to Random(15) and we get:
- 1 <= Random(15)+1 < 16... So we get the colors we want... :)
-
- Having done this, let's move on to more theory... The ideia is this:
-
- 1) Clear Stars
- 2) Move Stars
- 3) Draw Stars
- 4) Go back to step 1
-
- So, how do you do this, you may ask... Well, like this...
-
- Step 1: You just draw the stars in their positions, but in color 0 (or
- whatever is the color of your background). Remember to only clear
- the stars before you move them, or else you don't clear them,
- you'll just draw them in color 0 elsewhere !
-
- Procedure ClearStars;
- Var A:Word;
- Begin
- For A:=1 To 1000 Do PutPixel(Stars[A].X,Stars[A].Y,0,VGA);
- End;
-
- Step 2: You should give the ability to move the stars to every direction
- you may want... As this is a bidimensional starfield, you have
- 2 incrementation variables. The ideia is to sum to the coordinates
- of the stars a value given to the procedure.
-
- Procedure MoveStars(Ix,Iy:Integer);
- Var A:Integer;
- Begin
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Stars[A].X+Ix;
- Stars[A].Y:=Stars[A].Y+Iy;
- End;
- End;
-
- Now, let's assume you want to move the stars left... You just
- do MoveStars(-1,0); Easy, isn't it ?
- Wrong ! If you do like this, you can get an error... For example,
- let's assume:
- Stars[1].X:=0;
- Ix:=-1;
- If you execute the MoveStars procedure, you will get an error,
- because Stars[1].X is a variable of type Word, that doesn't allow
- negative numbers!
- The best way to fix this is to make the X and Y fields of the
- Star's record variables of type Integer and check if their are out
- of bounds... If they are, you wrap it around the screen.
- Wrap around the screen is a process that means that is a star has
- coordinates (0,10) and it is scrolled left, a new star will appear
- at (319,10)... So, the new procedure is like this:
-
- Procedure MoveStars(Ix,Iy:Integer);
- Var A:Integer;
- Begin
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Stars[A].X+Ix;
- Stars[A].Y:=Stars[A].Y+Iy;
- If Stars[A].X<0 Then Stars[A].X:=319;
- If Stars[A].X>319 Then Stars[A].X:=0;
- If Stars[A].Y<0 Then Stars[A].Y:=199;
- If Stars[A].Y>199 Then Stars[A].Y:=0;
- End;
- End;
-
- Step 3: Well this should be simple enough... You just draw the stars ! :)
-
- Procedure DrawStars;
- Var A:Word;
- Begin
- For A:=1 To 1000 Do
- PutPixel(Stars[A].X,Stars[A].Y,Stars[A].Color,VGA);
- End;
-
- Well, this is easy enough, right ? The whole program is here:
-
- Program Starfield;
-
- Uses Mode13h;
-
- Type Star=Record
- X,Y:Integer;
- Color:Byte;
- End;
-
- Var Stars:Array[1..1000] Of Star;
- A:Integer;
-
- Procedure Init;
- Var A:Word;
- Begin
- InitGraph;
- { Sets up 16 grays... }
- For A:=0 To 15 Do SetColor(A,A*4,A*4,A*4);
- { Sets up stars }
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Random(320);
- Stars[A].Y:=Random(200);
- Stars[A].Color:=Random(15)+1;
- End;
- End;
-
- Procedure ClearStars;
- Var A:Word;
- Begin
- For A:=1 To 1000 Do PutPixel(Stars[A].X,Stars[A].Y,0,VGA);
- End;
-
- Procedure MoveStars(Ix,Iy:Integer);
- Var A:Integer;
- Begin
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Stars[A].X+Ix;
- Stars[A].Y:=Stars[A].Y+Iy;
- If Stars[A].X<0 Then Stars[A].X:=319;
- If Stars[A].X>319 Then Stars[A].X:=0;
- If Stars[A].Y<0 Then Stars[A].Y:=199;
- If Stars[A].Y>199 Then Stars[A].Y:=0;
- End;
- End;
-
- Procedure DrawStars;
- Var A:Word;
- Begin
- For A:=1 To 1000 Do
- PutPixel(Stars[A].X,Stars[A].Y,Stars[A].Color,VGA);
- End;
-
- Procedure MoveAround(Ix,Iy:Integer);
- Begin
- ClearStars;
- MoveStars(Ix,Iy);
- DrawStars;
- End;
-
- Begin
- Init;
- For A:=1 To 100 Do MoveAround(-1,0);
- For A:=1 To 100 Do MoveAround(-1,1);
- For A:=1 To 100 Do MoveAround(0,1);
- For A:=1 To 100 Do MoveAround(1,1);
- For A:=1 To 100 Do MoveAround(1,0);
- For A:=1 To 100 Do MoveAround(1,-1);
- For A:=1 To 100 Do MoveAround(0,-1);
- For A:=1 To 100 Do MoveAround(-1,-1);
- Closegraph;
- End.
-
- So, if you run this, you realize that this FLICKER A LOT !! And that
- anoying ! Ok, to mend this, you should use virtual screens... The ideia is
- the same, differing only that you clear and draw the stars in the virtual
- screen and then you copy the virtual screen to the VGA screen... That will
- avoid the flicker... Program:
-
- Program VirtualStarfield;
-
- Uses Mode13h;
-
- Type Star=Record
- X,Y:Integer;
- Color:Byte;
- End;
-
- Var Stars:Array[1..1000] Of Star;
- A:Integer;
-
- Procedure Init;
- Var A:Word;
- Begin
- InitGraph;
- InitVirt;
- Cls(0,VP[1]);
- { Sets up 16 grays... }
- For A:=0 To 15 Do SetColor(A,A*4,A*4,A*4);
- { Sets up stars }
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Random(320);
- Stars[A].Y:=Random(200);
- Stars[A].Color:=Random(15)+1;
- End;
- End;
-
- Procedure ClearStars;
- Var A:Word;
- Begin
- For A:=1 To 1000 Do PutPixel(Stars[A].X,Stars[A].Y,0,VP[1]);
- End;
-
- Procedure MoveStars(Ix,Iy:Integer);
- Var A:Integer;
- Begin
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Stars[A].X+Ix;
- Stars[A].Y:=Stars[A].Y+Iy;
- If Stars[A].X<0 Then Stars[A].X:=319;
- If Stars[A].X>319 Then Stars[A].X:=0;
- If Stars[A].Y<0 Then Stars[A].Y:=199;
- If Stars[A].Y>199 Then Stars[A].Y:=0;
- End;
- End;
-
- Procedure DrawStars;
- Var A:Word;
- Begin
- For A:=1 To 1000 Do
- PutPixel(Stars[A].X,Stars[A].Y,Stars[A].Color,VP[1]);
- End;
-
- Procedure MoveAround(Ix,Iy:Integer);
- Begin
- ClearStars;
- MoveStars(Ix,Iy);
- DrawStars;
- WaitVbl;
- CopyPage(VP[1],VGA);
- End;
-
- Begin
- Init;
- For A:=1 To 100 Do MoveAround(-1,0);
- For A:=1 To 100 Do MoveAround(-1,1);
- For A:=1 To 100 Do MoveAround(0,1);
- For A:=1 To 100 Do MoveAround(1,1);
- For A:=1 To 100 Do MoveAround(1,0);
- For A:=1 To 100 Do MoveAround(1,-1);
- For A:=1 To 100 Do MoveAround(0,-1);
- For A:=1 To 100 Do MoveAround(-1,-1);
- Closegraph;
- CloseVirt;
- End.
-
- If you are smart, you already realized that this is slow... Again! Why ?
- Because you are moving 64000 bytes again, because of the virtual screen!
- So, what's the solution for the slowness ? Well, in my computer, there
- isn't !! But, in a good computer, you can try testing for the Vertical
- Retrace and clear and draw only when the electron beam is going up the
- screen... But, to clear and draw in a single retrace, you should avoid
- computing the movement of the stars, so you should use two arrays to store
- the before and after positions.
-
- Now, let's get to the real fun stuff... It was about time !!! This is
- getting to be the most boring article in 'The Mag'... As the matter of fact,
- this the most boring article of any mag!
- Ok, multi-speed scrolling! Well, stars that are at a greater distance from
- us tend to move slower relatively to us. So, you must compute the movement
- of the stars bearing in consideration the distance... But, because you don't
- have to add another variable that stores the distance, you can use the color
- variable, because a star that is farther from us is naturally less bright, so,
- the nearest the color is to 0, the slower it will move. The only thing that
- must be changed in the program is the procedure that computes the stars,
- the MoveStars procedure. It will became something like this:
-
- Procedure MoveStars(Ix,Iy:Integer);
- Var A:Integer;
- Begin
- For A:=1 To 1000 Do
- Begin
- Stars[A].X:=Stars[A].X+Ix*(Stars[A].Color Div 4);
- Stars[A].Y:=Stars[A].Y+Iy*(Stars[A].Color Div 4);
- If Stars[A].X<0 Then Stars[A].X:=319;
- If Stars[A].X>319 Then Stars[A].X:=0;
- If Stars[A].Y<0 Then Stars[A].Y:=199;
- If Stars[A].Y>199 Then Stars[A].Y:=0;
- End;
- End;
-
- You add to the coordinate of the star a value computed taking in acount
- the distance, that is, the brightness of the star...
- This gives 4 different speeds (16 different brightnesses DIV 4)... You
- could improve to use real values, instead of integer, and then have a greater
- flexibility...
- So, get coding and improve this code, because, altough it is better
- than last issue's code it just plain _SUCKS_ ! :) Have fun... :)
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 7. Sprites Part I - Introduction
-
- This is the first of a series of articles that teaches you how to create
- and use your vey own Sprite Engine... Sprites are a very important part in
- coding games and some demos... They are the vital part of games like R-Type,
- Street-Fighter and all games like that.
- This will be more like a image handling tutorial, but sprites are just
- that, images that move (or not) on the screen. In the end of this first part,
- you will be able to get an image from the screen, how to save and load images
- from disk, and to put an image in the screen.
-
- 7.1. Generating images
-
- This will teach you how to get an image from the screen.
- First of all, we need to know were to store it... The first think to come to
- mind is an array, but that isn't suitable to store an image, because we want
- to store images of different sizes, and an array has a fixed sized... So we
- need a structure whose size can be defined at run-time, rather than at
- compile time... So, who do you gonna call ? POINTERS !!!
- So, get 'The Mag', issue 7, for a complete explanation on how this
- particular way of handling pointers will work.
- So, the ideia is this:
-
- 1) Allocate the required space for the image
- 2) Get the image
-
- Let's start with number one... So, to allocate the space, we use the GetMem
- keyword, but we need to know how much space we want to allocate. Let's assume
- you are trying to make the GetImage procedure:
-
- Procedure GetImage(x1,y1,x2,y2:Word;Var Img:Pointer;Where:Word);
-
- This would get the image from (x1,y1) to (x2,y2) of page Where and store it
- in Img...
- Well, to store a pixel, you need a byte, well, to store a rectangular
- piece of image, you need x*y pixels, where x and y are the horizontal and
- vertical sizes, respectivelly. But, we also need to store the x and y sizes
- of the image, because we will need them to draw the image (to interpret the
- data store in the pointer, because that data won't be organized in a
- rectangule, but it will be stored as a line of bytes) and we need them also
- to deallocate the image, because we must know the size of the pointer to
- deallocate him... So, as the x and y are variables of type word, we need 2
- bytes for each, so we need 4 bytes for both. So, let's make the procedure:
-
- Procedure GetImage(x1,y1,x2,y2:Word;Var Img:Pointer;Where:Word);
- Var Dx,Dy:Word;
- A,B:Word;
- Segm,Offs:Word;
- Begin
- { Allocate memory }
- Dx:=Abs(x2-x1)+1;
- Dy:=Abs(y2-y1)+1;
- GetMem(Img,Dx*Dy+4);
- { Gets the segment and offset of pointer, to access the }
- { data indexed... }
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- { Stores x and y sizes of image }
- Move(Dx,Mem[Segm:Offs],2);
- Move(Dy,Mem[Segm:Offs+2],2);
- { Store the image }
- Offs:=Offs+4;
- For A:=y1 to y2 Do
- For B:=x1 to x2 Do
- Begin
- Mem[Segm:Offs]:=GetPixel(B,A,Where);
- Inc(Offs);
- End;
- End;
-
- Abs is a function that gives the absolute value of a number:
-
- Abs(5) = 5
- Abs(-5) = 5
-
- GetPixel is a function defined in the Mode13h unit (given with this issue
- of 'The Mag'). It takes three parameters (x,y and Where), and it gives out
- the color number of the pixel at (x,y) of page Where.
- So, we have the procedure that gets an image and store it... As in every
- pointer, we need to deallocate it at some moment in time (even at the end
- of the program). So, before I forget, how to...
-
- 7.2. Killing an image
-
- This is very simple... You just analise the x and y size of an image and
- deallocate the space given to the pointer.
- Code:
-
- Procedure KillImage(Var Img:Pointer);
- Var Dx,Dy:Word;
- Segm,Offs:Word;
- Begin
- { Get X and Y size of image }
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- Move(Mem[Segm:Offs+2],Dy,2);
- { Clear pointer }
- FreeMem(Img,Dx*Dy+4);
- End;
-
- Easy, isn't it ?
- Let's move on... It is no use getting an image if you can't show it...
-
- 7.3. Displaying an image
-
- Well, to display an image, you must go to the pointer and dump the data
- onto the screen... That's easy enough to do, and there are some ways to speed
- up that process.
- Let's image a 4x4 image, stored in thr Img pointer, and we want to place
- that image at some coordinates, (x,y).
-
- Img -> 04 00 04 00 FF FA A0 01 02 03 04 05 06 00 C0 30 20 10 EE 02
- ----- ----- ----------- ----------- ----------- -----------
- | | | | | |
- | | | | |--------| |
- | | | | | |
- | | |-----------|----- FF FA A0 01 | |
- | | |----- 02 03 04 05 | |
- | | 06 00 C0 30 __| |
- | | 21 10 EE 02 -----|
- | Y Size
- |
- X size
-
- Did you understand the above scheme ? We must translate a linear batch
- of bytes into a rectangular one... So:
-
- Procedure PutImage(X,Y:Integer;Var Img:Pointer;Where:Word);
- Var Dx,Dy:Word;
- A,B:Word;
- Segm,Offs:Word;
- Begin
- { Get X and Y size of image }
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- Move(Mem[Segm:Offs+2],Dy,2);
- { Draw the picture }
- Offs:=Offs+4;
- For A:=Y To Y+Dy-1 Do
- For B:=X To X+Dx-1 Do
- Begin
- PutPixel(B,A,Mem[Segm:Offs],Where);
- Inc(Offs);
- End;
- End;
-
- Yupi !! We have a PutImage procedure... But let's improve it... If you
- look closely at the scheme, you know that in you can transfer a line of the
- image at one, using the move command... So replace:
-
- For A:=Y To Y+Dy-1 Do
- For B:=X To X+Dx-1 Do
- Begin
- PutPixel(B,A,Mem[Segm:Offs],Where);
- Inc(Offs);
- End;
-
- With:
-
- For A:=Y To Y+Dy-1 Do
- Begin
- Move(Mem[Segm:Offs],Mem[Where:A*320+X],Dx);
- Offs:=Offs+Dx;
- End;
-
- There it is... A fast (Pascal thinking) routine to put images on the
- screen...
- Try to put an image in coordinates in a way the image goes off the screen...
- As you may see, the image wraps around the screen in the X direction. Well,
- this won't do for most games, so we must introduce:
-
- 7.4. Clipping
-
- Well, the ideia behind clipping is quite simple... You verify if the
- coordinates of a certain pixel are out of the screen, and if they are, you
- simply don't place it... This is obviosly slower than the normal PutImage,
- and you can't put the entire line all at once in the screen, but sometimes
- it's more usefull... So, you define the variables:
-
- MinX=0; MaxX=319;
- MinY=0; MaxY=199;
-
- This is the drawing window... Making this definitions you gain flexibility,
- because you gain the ability to clip the images to a part of the screen, not
- only to all of the screen.
- So, adapting the first PutImage procedure:
-
- Procedure PutImage_C(X,Y:Integer;Var Img:Pointer;Where:Word);
- Var Dx,Dy:Word;
- A,B:Word;
- Segm,Offs:Word;
- Begin
- { Get X and Y size of image }
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- Move(Mem[Segm:Offs+2],Dy,2);
- { Draw the picture }
- Offs:=Offs+4;
- A:=Y;
- While (A<=Y+DY-1) And (A<MaxY) Do
- Begin
- B:=X;
- While (B<=X+DX-1) And (B<MaxX) Do
- Begin
- If (X>=MinX) And (Y>=MinY) Then
- PutPixel(B,A,Mem[Segm:Offs],Where);
- Inc(Offs);
- Inc(B);
- End;
- Inc(A);
- End;
- End;
-
- We use a While cicle instead of a For cicle, because if you think a bit,
- notice that if an X value is larger than the maximum X value permited, then
- all the X values of that line are also out of bounds, so no use in testing
- them... And the same for the Y values, so the use the while cicles to test
- it. So, inside the loops, we only need to test if the coordinates are bigger
- than the minimum values...
- You should choose carefully which one of the routines (with or without
- clipping) to use in your program, because the routine without clipping is
- a lot faster and is most usefull if certain cases...
-
- 7.5. Saving to the disk
-
- Sometimes, you can't generate all the images you want in your programs,
- so you must load them from disk. But, to load to the disk, you have to save
- it first...
- To do so, you have to choose a format. I usually use a quite simple one:
- four bytes with the x and y sizes, and then the bitmap information... This
- way you can save and load directly from and to the pointer.
- So, let's make the procedure:
-
- Procedure SaveImage(Var F:File;Img:Pointer);
- Var Dx,Dy:Word;
- Segm,Offs:Word;
- Begin
- { Get X and Y size of image }
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Mem[Segm:Offs],Dx,2);
- Move(Mem[Segm:Offs+2],Dy,2);
- { Save the data }
- BlockWrite(F,Img^,Dx*Dy+4);
- End;
-
- We assume the parameter F (of type file) is already an opened file for
- writing. Why don't we open the file to write and close it within the
- procedure ?
- Well, because you may want to save more than one picture in a file, and
- if you did so, you only would be able to save one image.
- Now, let's pass on to:
-
- 7.6. Loading from the disk
-
- I'll don't even bother explaining the loading procedure... It is _SO_
- simple !! You read the size, and you get the memory for the pointer... Then,
- you just shoot the data to the pointer! Simple, isn't it ?
-
- Procedure LoadImage(Var F:File;Var Img:Pointer);
- Var Dx,Dy:Word;
- Segm,Offs:Word;
- Begin
- { Get X and Y size of image }
- BlockRead(F,Dx,2);
- BlockRead(F,Dy,2);
- { Get the memory }
- GetMem(Img,Dx*Dy+4);
- { Store X and Y sizes }
- Segm:=Seg(Img^);
- Offs:=Ofs(Img^);
- Move(Dx,Mem[Segm:Offs],2);
- Move(Dy,Mem[Segm:Offs+2],2);
- { Store the image }
- Offs:=Offs+4;
- BlockWrite(F,Mem[Segm:Offs],Dx*Dy);
- End;
-
- So, here ends the first part of the sprites tutorial... Hope you enjoyed.
- Just a note: I've put all the procedures given in this issue in an unit
- called Images. That unit will be further expanded in the next issues, so
- make sure you update it...
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 8. Graphics Part VI - Scrolling Part II
-
- As you may have gussed already, this is the continuation of last issue's
- graphics seccion...
- In this issue, we will delve into other forms of scrolling, more complex
- ones... Not more complicated, just more complex.
-
- 8.1. Tile scrolling
-
- You know the Ultima games ? (of course you know them ! Everybody knows
- them !!)...
- Well, they use this type of scrolling... What's the ideia ? Think about
- this: imagine you wanted to do a game and you wanted to scroll around in a
- playfield made up of 10 full screens... Well, you know a screen uses 64000
- bytes, so 10 screens would use 640000 bytes ! That almost all base memory !
- And a game with 10 screens isn't that big !! One of my old games had a
- playfield with almost 500 screens !!!
- But, if you think for a while you will come to the conclusion that in so
- many screens some things are going to be repeated... Imagine that the
- playfield is a grassland, with some trees... Well, that's were the concept
- of tilling comes to action...
- You must have some sort of a map and some graphics... The map will tell
- which graphics go to which places... So, like a puzzle, you build the image
- of small tiles.
- I'll only explain this method in a simple way, because I'm intending to do
- a whole article on them soon, because there is so much to know about them...
- So, let's put this into practice... You already know how to read and display
- images, so you must only to use following procedure to display a certain
- part of the map:
-
- Procedure DispGeo(X,Y,DX,DY,Where:Word);
- Var A,B:Word;
- Begin
- For A:=0 To DX-1 Do
- For B:=0 To DY-1 Do
- PutImage(A*16,B*16,GeoImages[GeoMap[X+A,Y+B]]^,Where);
- End;
-
- Looks confusing ? It isn't... I'll explain... This procedure displays in
- coordinates (0,0) of the page choosen by the Where parameter the zone of the
- map that goes from (X,Y) to (X+DX,Y+DY). Don't confuse the x and y
- coordinates of the screen (or virtual page) with the x and y coordinates
- of the map.
- The map should be stored in the GeoMap array (this can be loaded or
- generated by the program), and the images (the tiles) should be loaded to
- the GeoImages array of pointers... This can be done with the following
- procedure:
-
- Procedure LoadGeoImages(Filename:String);
- Var F:File;
- Index:Word;
- Begin
- Assign(F,Filename);
- Reset(F,1);
- Index:=1;
- While Not Eof(F) Do
- Begin
- LoadImage(F,GeoImages[Index]);
- Inc(Index);
- End;
- End;
-
- This loads all images available in a file to an array called GeoImages.
- In the example I'm making, the tiles are 16x16 pixels... That is the
- reason of the multiplication for 16 in the DispGeo procedure.
- An example of a procedure that generates a GeoMap is:
-
- Procedure GenGeoMap;
- Var A,B:Word;
- Begin
- For A:=0 To GeoMapSizeX Do
- For B:=0 To GeoMapSizeY Do
- GeoMap[A,B]:=Random(5)+1;
- End;
-
- This fills the GeoMap with random tiles, ranging from 1 to 5.
- Now, to scroll around this map, you just have to call the DispGeo procedure
- with different X and Y values (don't alter the Dx and Dy values, or else
- you'll get funny results on the screen).
- There is a test program that uses the above procedure with this mag...
- It is called ScrlGeo.Pas... It uses the file ScrlGeo.Img that stores the
- images of the trees.
- So, the basics to get you going is taught... Use this knowledge wisely,
- my child... :)
-
- 7.2. Parallax scrolling
-
- Some computers (like the Amiga) have built-in circuits that handle parallax
- scrolling, but in the PC, you have to code yourself your parallax engine...
- But, what is parallax scrolling... Well, parallax scrolling is similar to
- what I have done with the starfield effect in this issue (see article 6).
- Objects that are further away from us appear to move slower, so you must
- scroll them at different times... What I'm going to teach is a combination
- of two scrolls... For example, check the Prllx01.Pas program... This scrolls
- a piece of land, with some water on the sides... It uses the theory of
- scrolling of the last issue.
- Now, check the Prllx02.Pas program... It is similar in most respects,
- differing only in the fact that it scrolls clouds...
- Now, let's combine the two together !
- As we want to make parallax scrolling, you must make sure that the clouds
- move faster than the land, so let's do it like this: while the land scrolls
- one pixel, the clouds scroll two pixels ! Then, for every frame, we just have
- to combine the two scrolls... To do so, we draw the land and then we draw
- the clouds, making sure that only the white parts of the cloud are drawn,
- not the black parts. To do so, we have to check each pixel of the image to
- put on top... So, we have to modify the CopyPage procedure... Here is the
- new one (the T stands for Transparency):
-
- Procedure CopyPage_T(From,Too:Word);
- Var Offs:Word;
- Begin
- For Offs:=0 To 63999 Do
- If Mem[From:Offs]<>0 Then Mem[Too:Offs]:=Mem[From:Offs];
- End;
-
- Then, you just alter the procedure that calls the scrolls, in a way that
- it scrolls two times the clouds before scrolling once the land... And voilá,
- you have parallax scrolling... It's all in the Prllx03.Pas file... This is
- _VERY_SLOW_, but it is only to demonstrate... In future issues I will teach
- you how to do this in assembler and that will _REALLY_ speed up that thing...
-
- 7.3. Partial scrolls
-
- This final part talks about partial scrolls... That's an easy concept to
- grasp... To partially scroll anything, independent from the direction, the
- ideia is to move one line (or part of a line) at a time... I'll give you the
- procedures that do this, and you dissect them as you will:
-
- Procedure ScrollUp(x1,y1,x2,y2,Where:Word);
- Var A:Word;
- Begin
- For A:=y1 To y2 Do
- Move(Mem[Where:A*320+x1],Mem[Where:(A-1)*320+x1],x2-x1);
- End;
-
- Procedure ScrollDown(x1,y1,x2,y2,Where:Word);
- Var A:Word;
- Begin
- For A:=y2 DownTo y1 Do
- Move(Mem[Where:A*320+x1],Mem[Where:(A+1)*320+x1],x2-x1);
- End;
-
- Procedure ScrollLeft(x1,y1,x2,y2,Where:Word);
- Var A:Word;
- Begin
- For A:=y1 To y1 Do
- Move(Mem[Where:A*320+x1],Mem[Where:A*320+x1-1],x2-x1);
- End;
-
- Procedure ScrollRigth(x1,y1,x2,y2,Where:Word);
- Var A:Word;
- Begin
- For A:=y1 To y1 Do
- Move(Mem[Where:A*320+x1],Mem[Where:A*320+x1+1],x2-x1);
- End;
-
- I think this is fairly simple to understand... The ScrollLeft and
- ScrollRight procedures haven't changed much, but in full screen scrolls we
- could move the entire screen up and down with just one intruction, but with
- partial scrolls we must move it line by line...
- Well, this is the end of the scrolling saga... I think I've covered almost
- everything, except tile-scrolling, that will be discussed in detail a future
- issue...
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 9. Hints and Tips
-
- * - Begginners tip
- ** - Medium tip
- *** - Advanced tip
-
-
- - Logic operations on ilogic operands (**)
-
- Well, I'm loosing my brain thinking about something to put here... I can't
- remember nothing...
- Ok, I remember something... Did you knew you could do logical operation
- such as AND, OR and NOT with operands of any kind ?
- You may ask, how does this work ???? Well, like this... Imagine the
- internal (binary) representation of the number 41:
-
- 41 = 00101001 ; Then you ANDit with number 1:
- 1 = 00000001 ; The result is:
- 00000001 ; He makes the logic corresponding with
-
- the logic tables I have given you... Similiarly:
-
- OR: NOT:
-
- 00101001 NOT 00101001 =
- OR 00000010 11010110
- = 00101010
-
- This is quite usefull sometimes, because logic operations are much faster
- than aritmetic options... There are quite nifty tricks to do with this,
- but I'll leave that for other issue... :)
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-
-
- 10. Points of View
-
- Ooff !! I'm tired... Almost 80000 bytes this one !! That's 15000 more than
- the second larger issue...
- Well, what can I say in this issue's point of view ?
- I really don't know... I'll satrt by telling what I'm going to put in the
- next issue... I'll continue the Sprites series (talk about transparency,
- animation and movement), the Graphics Series (I'll talk about text in mode
- 13h)... I'll also do part II of the 'Building a text adventure' tutorial
- (talking about the parser and basic commands). I'll also start a tutorial
- on 'How to make a program 100% in assembler'... And I'm thinking of making
- another article on effects coding... I think that is going to be another
- _LARGE_ issue ! :)
- I don't know when is issue 9 be ready, because I'm going into projects
- time at the university (couple of works in assembly, one in Modula 2 and
- another in C)... And also, I must study a bit (if I want to pass the
- semester alive :) Also, I'm working on a game (won't tell you anything about
- it !! It's a secret), I'm making a talker and a MUD, and also a demo (all
- I'm going to say about this one here is the name: Into The Shadows !! Neat,
- isn't it ?). I don't know were I'll get the time to do this all, but I'm
- going to try...
- Well, this points of view are sucking big time !! As all this issue...
- Ok, I'll leave you with a question ?
- Am I beginning to be more serious in 'The Mag' ? Am I growing old and
- less funnier ? Hope not... :) But I feel I'm not as a comediant as I used to
- be... Maybe I've run out of jokes... Or maybe I'm just tired (after all,
- 80000 bytes !!!)... So, to give you some humor, here's a couple of jokes:
-
- How many Microsoft programmers are needed to screw a lightbulb ?
- None !! They just change the standart ! :))))
-
- 'Who the hell in General Failure and why is he reading my disk ???'
-
- -x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x-x
-
- 11. The adventures of Spellcaster, the rebel programmer of year 2018.
-
- Episode 8 - Suicide
-
- The upgrading of our jetcar was going well... We were trying to hook up a
- Durallium block to the front of it, and to do so we needed to increase the
- power of the engine.
- - Has anyone ever told you that you are insane ? - Deathripper asked me.
- - Yep... - I answered, without taking my eyes of the drone that was lifting
- the heavy block. - Am I cool or what ?
- - No, you are insane... You are a suicidal maniac...
- - Well, suicide is quite fun, if you look at it with a nice perspective - I
- replied, with a grim look in my face and a dark tone of voice.
- - As the matter of fact, I'm the crazy one, going after this psicho's plans
- like this... - Karl muttered to himself, kicking a bolt and looking at his
- sister, that was working on the engine of the craft.
- - Well, this "psycho", as you called me can't code jack-shit, - I said,
- looking at Kristie with hatred in his eyes, remembering what she said about
- him about a week ago. - but I was the one that made this thing possible...
- - Oh, let's all kneel at the feet of the Great Lord Spellcaster, Master of
- Assembly Coding and Ruler of Gourad Shading !! - Excalibur said, ironically.
- - Shut the hell up, Kristie... - I shouted, my voice echoing in the cold
- closed room. - You shouldn't talk of what you don't know... - I said, with
- a cold emontionless voice.
- - Why do you stand up to this piece of shit, Karl ??!!! - She asked, waving
- her arms frantically.
- - Well... He's got a point... All we ever do is say that he can't code,
- altough the only thing we used so far to destroy Comptel is his virus...
- We are beeing unfair...
- - You are ?! - I asked, surprised. - Yes, of course you are... - I continued,
- trying to hide the surprise in my voice.
- - WHAT ?! - Excalibur shouted. - ARE YOU PAYING HEED TO A GUY THAT LOOKS LIKE
- HE HAS COME FROM THE VISUAL BASIC KINDERGARTEN ?!!! - Her voice then
- changed to a more friendly tone, yet filled with anger. - Well, in that
- case I'm OUT of your stupid and suicidal plan...
- She got up from beneath the jetcar and she opened the door of the garage.
- The sunlight hurted my eyes, and I look at her perfect body's shadow, thinking
- of the reasons that make me fight with her, when I knew, deep in my heart
- that I loved her. She swang her head, making her black hair fly in the wind,
- and she look directly at me... I could be wrong, but in her eyes there was
- much more than just hatred... I just didn't knew what it was... Then she
- turned over again and she left the garage.
- - Well, Gundsen, it looks like we don't have a pilot for the jetcar... - I
- said in a sad voice.
- - Don't worry... She'll be back... She always does... And after all, her hate
- for William Gates is so deep in her that she can forget any other hatred.
- I stood there in silent for awhile. Then I broke the silence with a question:
- - Why does she hate Gates so much ?
- - I know why... But only she can tell you...
- The garage fell in silence again... I looked at Gundsen, and his eyes were
- staring at me, as he could read my thoughs. He said, smilling:
- - No, I don't think she hates you at all...
- And saying this, he also leaved the garage and I was left alone with my
- thoughs, wondering if my feelings for Kristie were indeed so deep and visible
- as it seemed...
-
-
- See you in the next issue
- Diogo "SpellCaster" Andrade